/*jshint node:true*/
'use strict';


function isUndefined(value) {
    return value === void 0;
}

/**
 * Pagination Class
 * @param {object} options [options object]
 */
function Pagination(options) {
    this.validateOptions(options);

    // required properties
    this.currentPage = options.currentPage;
    this.totalItems = options.totalItems;
    this.itemsPerPage = options.itemsPerPage;

    // default properties
    this.firstPage = isUndefined(options.firstPage) ? 1 : options.firstPage;
    this.rangeLength = options.rangeLength || 5;
    this.firstLabel = options.firstLabel || '«';
    this.previousLabel = options.previousLabel || '‹';
    this.nextLabel = options.nextLabel || '›';
    this.lastLabel = options.lastLabel || '»';

    // processed properties
    this.offset = this.getOffset();
    this.totalPages = this.getTotal();
    this.lastPage = this.firstPage + this.totalPages - 1;
    this.nextPage = this.getNext();
    this.previousPage = this.getPrevious();
    this.rangeStart = this.getRangeStart();
    this.rangeEnd = this.getRangeEnd();
    this.range = this.getRange();
}

/**
 * validate required options
 * @param {object} options [options object]
 */
Pagination.prototype.validateOptions = function (options) {
    if (!options) {
        throw new Error('No `options` were passed, aborting.');
    }

    if (isUndefined(options.currentPage) || !options.totalItems || !options.itemsPerPage) {
        throw new Error('You must define your options object correctly, aborting.');
    }

    if (isNaN(options.currentPage) || isNaN(options.totalItems) || isNaN(options.itemsPerPage)) {
        throw new Error('Your options object properties should be numbers, aborting.');
    }
};

/**
 * get range offset
 * @return {number} [range offset]
 */
Pagination.prototype.getOffset = function () {
    return Math.floor(this.rangeLength / 2);
};

/**
 * get total pages
 * @return {number} [next page number]
 */
Pagination.prototype.getTotal = function () {
    return Math.ceil(this.totalItems / this.itemsPerPage);
};

/**
 * get next page
 * @return {number} [next page number]
 */
Pagination.prototype.getNext = function () {
    var next = this.currentPage + 1;
    return next > this.lastPage ? null : next;
};

/**
 * get previous page
 * @return {number} [previous page number]
 */
Pagination.prototype.getPrevious = function () {
    var previous = this.currentPage - 1;
    return previous < this.firstPage ? null : previous;
};

/**
 * get first item of the range
 * @return {number} [first item of the range]
 */
Pagination.prototype.getRangeStart = function () {
    var rangeStart;

    rangeStart = this.currentPage - this.offset;
    rangeStart = this.lastPage < rangeStart + this.rangeLength ? this.lastPage - this.rangeLength + 1 : rangeStart;
    rangeStart = rangeStart < this.firstPage ? this.firstPage : rangeStart;

    return rangeStart;
};

/**
 * get first item of the range
 * @return {number} [first item of the range]
 */
Pagination.prototype.getRangeEnd = function () {
    var rangeEnd;

    rangeEnd = this.currentPage + this.offset;
    rangeEnd = rangeEnd < this.rangeLength ? this.rangeLength : rangeEnd;
    rangeEnd = rangeEnd > this.lastPage ? this.lastPage : rangeEnd;

    return rangeEnd;
};

/**
 * get range array
 * @return {array} [array of range items]
 */
Pagination.prototype.getRange = function () {
    var range = [];
    var i = this.rangeStart;
    var t = this.rangeEnd;

    if (this.firstPage !== this.currentPage) {
        range.push({page: this.firstPage, isFirst: true, label: this.firstLabel});
    }

    if (this.previousPage !== null) {
        range.push({page: this.previousPage, isPrevious: true, label: this.previousLabel});
    }

    for (i; i <= t; i++) {
        var item = {page: i};

        if (i === this.currentPage) {
            item.isCurrent = true;
        }

        range.push(item);
    }

    if (this.nextPage) {
        range.push({page: this.nextPage, isNext: true, label: this.nextLabel});
    }

    if (this.lastPage !== this.currentPage) {
        range.push({page: this.lastPage, isLast: true, label: this.lastLabel});
    }

    return range;
};

/**
 * public
 */
module.exports = Pagination;
